package com.campus.merchant.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.campus.common.bean.common.Resp;
import com.campus.common.constants.GlobalConstant;
import com.campus.merchant.entity.Merchant;
import com.campus.merchant.entity.MerchantUser;
import com.campus.merchant.mapper.MerchantMapper;
import com.campus.merchant.mapper.MerchantUserMapper;
import com.campus.merchant.vo.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
public class WechatAuthService {
    private static final String GET_ACCESS_TOKEN_URL =
            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    @Value("${wechat.appid}")
    private String appid;

    @Value("${wechat.secret}")
    private String secret;

    @Value("${campus.profit.service-fee-rate}")
    private Double serviceFeeRate;
    
    @Value("${campus.wechat.transaction-fee-rate}")
    private double wechatTransactionFeeRate;
    
    @Value("${campus.wechat.max-split-rate}")
    private double wechatMaxSplitRate;

    @Autowired
    private MerchantUserMapper merchantUserMapper;

    @Autowired
    private RedisService redisService;

    // accessToken有效期（秒）
    private static final long ACCESS_TOKEN_EXPIRE = 1800; // 30分钟
    // refreshToken有效期（秒）
    private static final long REFRESH_TOKEN_EXPIRE = 7 * 86400L; // 7天
    @Autowired
    private MerchantMapper merchantMapper;



    /**
     * 获取小程序全局唯一后台接口调用凭据AccessToken
     * @return
     */
    public String getAccessToken() {
        String accessTokenInRedis = redisService.get(GlobalConstant.WECHAT_ACCESS_TOKEN + appid);

        if(StringUtils.isNotBlank(accessTokenInRedis)){
            return accessTokenInRedis;
        }

        String url = String.format(GET_ACCESS_TOKEN_URL, appid, secret);
        String result = HttpUtil.get(url, StandardCharsets.UTF_8);

        log.info("获取accessToken接口返回结果：{}", result);

        JSONObject resultJO = JSONUtil.parseObj(result);

        String accessToken = resultJO.getStr("access_token");
        Long expiresIn = resultJO.getLong("expires_in");

        //TODO 保存到redis
        if(StringUtils.isNotBlank(accessToken)){
            redisService.set(GlobalConstant.WECHAT_ACCESS_TOKEN + appid, accessToken, expiresIn-100);
        }

        return accessToken;
    }

    /**
     * 微信小程序静默登录
     * @param code 微信登录code
     * @return Resp 包含accessToken、refreshToken和用户信息
     */
    public Resp wxLogin(String code) {
        String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                appid, secret, code);

        String responseBody = HttpUtil.get(url);
        JSONObject response = JSONUtil.parseObj(responseBody);
        if (response == null || response.containsKey("errcode")) {
            return Resp.error("微信登录失败: " + (response != null ? response.getStr("errmsg") : "未知错误"));
        }

        String openid = response.getStr("openid");
        String sessionKey = response.getStr("session_key");

        // 查询或创建商家用户
        MerchantUser user = merchantUserMapper.selectOne(Wrappers.lambdaQuery(MerchantUser.class).eq(MerchantUser::getOpenid, openid));
        if (user == null) {
            user = new MerchantUser();
            user.setOpenid(openid);
            merchantUserMapper.insert(user);
        }

        // 生成accessToken和refreshToken
        String accessToken = generateToken(user, "access");
        String refreshToken = generateToken(user, "refresh");

        // 存入redis
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        userInfoVo.setToken(accessToken);
        redisService.set(accessToken, JSON.toJSONString(userInfoVo), ACCESS_TOKEN_EXPIRE);
        redisService.set(refreshToken, JSON.toJSONString(userInfoVo), REFRESH_TOKEN_EXPIRE);

        //根据用户ID查询商户ID
        Merchant merchant = merchantMapper.selectOne(Wrappers.lambdaQuery(Merchant.class).eq(Merchant::getMerchantUserId, user.getId()));

        // 根据微信分账规则计算配送费与实付金额的比率
        // 微信分账限制：订单实付金额×(1-微信手续费)×最大分账比例 - 订单实付金额×运营平台抽佣比例 ≥ 配送费
        // 即：实付金额×((1-微信手续费)×最大分账比例 - 运营平台抽佣比例) ≥ 配送费
        // 所以：配送费/实付金额 ≤ (1-微信手续费)×最大分账比例 - 运营平台抽佣比例
        double availableSplitRate = (1 - wechatTransactionFeeRate) * wechatMaxSplitRate - serviceFeeRate;
        double deliveryFeeRatio = 1.0 / availableSplitRate;

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", accessToken);
        result.put("refreshToken", refreshToken);
        result.put("userInfo", userInfoVo);
        result.put("deliveryFeeRatio", deliveryFeeRatio);
        if (merchant != null) {
            result.put("merchantId", merchant.getId());
        }
        return Resp.success(result);
    }

    /**
     * 刷新token
     * @param refreshToken refreshToken
     * @return Resp 新accessToken和refreshToken
     */
    public Resp refreshToken(String refreshToken) {
        // 校验refreshToken
        String userInfoStr = redisService.get(refreshToken);
        if (userInfoStr == null) {
            return Resp.error("refreshToken无效或已过期");
        }
        UserInfoVo userInfoVo = JSON.parseObject(userInfoStr, UserInfoVo.class);
        // 生成新accessToken和refreshToken
        MerchantUser user = new MerchantUser();
        BeanUtils.copyProperties(userInfoVo, user);
        String newAccessToken = generateToken(user, "access");
        String newRefreshToken = generateToken(user, "refresh");
        // 存入redis
        userInfoVo.setToken(newAccessToken);
        redisService.set(newAccessToken, JSON.toJSONString(userInfoVo), ACCESS_TOKEN_EXPIRE);
        redisService.set(newRefreshToken, JSON.toJSONString(userInfoVo), REFRESH_TOKEN_EXPIRE);
        // 删除旧refreshToken
        redisService.remove(refreshToken);
        // 返回新token
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", newAccessToken);
        result.put("refreshToken", newRefreshToken);
        return Resp.success(result);
    }

    /**
     * 生成token
     */
    private String generateToken(MerchantUser user, String type) {
        return MD5.create().digestHex((user.getOpenid() != null ? user.getOpenid() : "merchant") + type + UUID.randomUUID().toString() + DateTime.now().toString("yyyyMMddHHmmss"));
    }
}